
package jp.ize.iwp.avm1.display;

// {{{ imports

import flash.MovieClip;
import jp.ize.iwp.avm1.events.EventDispatcher;
import jp.ize.iwp.avm1.events.MouseEvent;
import jp.ize.iwp.avm1.text.TextField;

// }}}

class Sprite extends EventDispatcher
{
	// {{{ properties

	public var id:String;
	public var graphics:MovieClip;
	public var classname:String;

	public static var index:Int = 0;
	public static var prefix:String = "__iwp";

	public var x(getX,setX):Float;
	public var y(getY,setY):Float;
	public var alpha(getAlpha,setAlpha):Float;
	public var visible(getVisible,setVisible):Bool;
	public var mouseEnabled(getMouseEnabled,setMouseEnabled):Bool;
	public var numChildren(getNumChildren,setNumChildren):Int;

	public var children:Array<Dynamic>;

	public var _mouseEnabled:Bool;

	// }}}
	// {{{ public function new() : Void

	public function new() : Void
	{
		super();
		mouseEnabled = true;
		untyped {
			classname = this.__class__.__name__.join(".");
		}
		id = prefix + Std.string(index);
		index++;

		children = new Array();
	}

	// }}}
	// {{{ public function setParent( p:Dynamic ) : Void

	public function setParent( p:Dynamic ) : Void
	{
		if ( Std.is(p,MovieClip) ) {
			graphics = p.createEmptyMovieClip(id,p.getNextHighestDepth());
		} else if ( Std.is(p,Sprite) ){
			graphics = p.graphics.createEmptyMovieClip(id,p.graphics.getNextHighestDepth());
		}
		initMovieClip();
	}
	
	// }}}
	// {{{ public function initMovieClip() : Void

	public function initMovieClip() : Void
	{
		graphics.drawEllipse   = __drawEllipse( graphics );
		graphics.drawCircle    = __drawCircle( graphics );
		graphics.drawRect      = __drawRect( graphics );
		graphics.drawRoundRect = __drawRoundRect( graphics );
		if ( mouseEnabled ) {
			graphics.onMouseDown   = __onMouseDown( this );
			graphics.onMouseUp     = __onMouseUp( this );
			graphics.onMouseMove   = __onMouseMove( this );
			graphics.onRollOver    = __onRollOver( this );
			graphics.onRollOut     = __onRollOut( this );
		}
		visible = true;
	}

	// }}}

	// {{{ public function addChild( child:Dynamic ) : Void

	public function addChild( child:Dynamic ) : Void
	{
		children.push( child );
		child.setParent( graphics );
	}

	// }}}
	// {{{ public function removeChild( child:Dynamic ) : Void

	public function removeChild( child:Dynamic ) : Void
	{
		children.remove( child );
		if ( Std.is(child,Sprite) ) {
			var sp:Sprite = child;
			sp.remove();
		} else if ( Std.is(child,TextField) ) {
			var tf:TextField = child;
			tf.remove();
		}
	}

	// }}}
	// {{{ public function remove() : Void

	public function remove() : Void
	{
		graphics.unloadMovie();
	}

	// }}}

	// {{{ public function getX() : Float
	
	public function getX() : Float
	{
		return graphics._x;
	}

	// }}}
	// {{{ public function setX( v:Float ) : Float
	
	public function setX( v:Float ) : Float
	{
		graphics._x = v;
		return v;
	}

	// }}}
	// {{{ public function getY() : Float
	
	public function getY() : Float
	{
		return graphics._y;
	}

	// }}}
	// {{{ public function setY( v:Float ) : Float
	
	public function setY( v:Float ) : Float
	{
		graphics._y = v;
		return v;
	}

	// }}}
	// {{{ public function getAlpha() : Float
	
	public function getAlpha() : Float
	{
		return graphics._alpha;
	}

	// }}}
	// {{{ public function setAlpha( v:Float ) : Float
	
	public function setAlpha( v:Float ) : Float
	{
		graphics._alpha = v;
		return v;
	}

	// }}}
	// {{{ public function getVisible() : Bool
	
	public function getVisible() : Bool
	{
		return graphics._visible;
	}

	// }}}
	// {{{ public function setVisible( v:Bool ) : Bool
	
	public function setVisible( v:Bool ) : Bool
	{
		for ( child in children ) {
			child.visible = v;
		}
		graphics._visible = v;
		return v;
	}

	// }}}
	// {{{ public function getMouseEnabled() : Bool
	
	public function getMouseEnabled() : Bool
	{
		return _mouseEnabled;
	}

	// }}}
	// {{{ public function setMouseEnabled( v:Bool ) : Bool
	
	public function setMouseEnabled( v:Bool ) : Bool
	{
		_mouseEnabled = v;
		if ( _mouseEnabled ) {
			graphics.onMouseDown   = __onMouseDown( this );
			graphics.onMouseUp     = __onMouseUp( this );
			graphics.onMouseMove   = __onMouseMove( this );
			graphics.onRollOver    = __onRollOver( this );
			graphics.onRollOut     = __onRollOut( this );
		} else {
			Reflect.deleteField(graphics,"onMouseDown");
			Reflect.deleteField(graphics,"onMouseUp");
			Reflect.deleteField(graphics,"onMouseMove");
			Reflect.deleteField(graphics,"onRollOver");
			Reflect.deleteField(graphics,"onRollOut");
		}
		return v;
	}

	// }}}
	// {{{ public function getNumChildren() : Int
	
	public function getNumChildren() : Int
	{
		return children.length;
	}

	// }}}
	// {{{ public function setNumChildren( v:Int ) : Int
	
	public function setNumChildren( v:Int ) : Int
	{
		return v;
	}

	// }}}

	// {{{ public function startDrag(?lockCenter : Bool, ?bounds : Rectangle) : Void

	public function startDrag(?lockCenter : Bool, ?bounds : Dynamic) : Void
	{
		graphics.startDrag( lockCenter );
	}

	// }}}
	// {{{ public function stopDrag() : Void

	public function stopDrag() : Void
	{
		graphics.stopDrag();
	}

	// }}}
	// {{{ public function setChildIndex( s:Dynamic, index:Int ) : Void

	public function setChildIndex( s:Dynamic, index:Int ) : Void
	{
		var i:Int = index;
		if ( s.graphics.getDepth()!=this.numChildren-1 ) {
			s.graphics.swapDepths( i );
			i--;
			var ary:Array<Dynamic> = new Array();
			for ( child in children ) {
				ary.push( child );
			}
			ary.sort( function( a:Dynamic, b:Dynamic ) : Int {
				var adep:Int = a.graphics.getDepth();
				var bdep:Int = b.graphics.getDepth();
				if ( adep>bdep ) { 
					return -1;
				} else if ( adep==bdep ) { 
					return 0;
				}
				return 1;
			});
			while ( i>0 ) {
				ary[i].graphics.swapDepths(i-1);
				i--;
			}
		}
	}

	// }}}

	// {{{ public function __drawEllipse( obj:Dynamic ) : Dynamic

	public function __drawEllipse( obj:Dynamic ) : Dynamic
	{
		return function ( x:Float, y:Float, w:Float, h:Float ) {
			var pi:Float = Math.PI;
			var ar:Float = w/2;
			var br:Float = h/2;
			var cx:Float = x + ar;
			var cy:Float = y + br;
			var tanpi8:Float = Math.tan(pi/8);
			var cospi4:Float = Math.cos(pi/4);
			var sinpi4:Float = Math.sin(pi/4);
			obj.moveTo(ar + cx, 0 + cy);
			obj.curveTo(ar + cx, (br * tanpi8) + cy, (ar * cospi4) + cx, (br * sinpi4) + cy);
			obj.curveTo((ar * tanpi8) + cx, br + cy, 0 + cx, br + cy);
			obj.curveTo(((-ar) * tanpi8) + cx, br + cy, ((-ar) * cospi4) + cx, (br * sinpi4) + cy);
			obj.curveTo((-ar) + cx, (br * tanpi8) + cy, (-ar) + cx, 0 + cy);
			obj.curveTo((-ar) + cx, ((-br) * tanpi8) + cy, ((-ar) * cospi4) + cx, ((-br) * sinpi4) + cy);
			obj.curveTo(((-ar) * tanpi8) + cx, (-br) + cy, 0 + cx, (-br) + cy);
			obj.curveTo((ar * tanpi8) + cx, (-br) + cy, (ar * cospi4) + cx, ((-br) * sinpi4) + cy);
			obj.curveTo(ar + cx, ((-br) * tanpi8) + cy, ar + cx, 0 + cy);		
		}
	}

	// }}}
	// {{{ public function __drawCircle( obj:Dynamic ) : Dynamic

	public function __drawCircle( obj:Dynamic ) : Dynamic
	{
		return function ( cx:Float, cy:Float, r:Float ) {
			obj.drawEllipse(cx-r, cy-r, r*2, r*2);
		}
	}

	// }}}
	// {{{ public function __drawRect( obj:Dynamic ) : Dynamic

	public function __drawRect( obj:Dynamic ) : Dynamic
	{
		return function ( x:Float, y:Float, w:Float, h:Float ) {
			obj.moveTo(x,  y);
			obj.lineTo(x+w,y);
			obj.lineTo(x+w,y+h);
			obj.lineTo(x,  y+h);
			obj.lineTo(x,  y);
		}
	}

	// }}}
	// {{{ public function __drawRoundRect( obj:Dynamic ) : Dynamic

	public function __drawRoundRect( obj:Dynamic ) : Dynamic
	{
		return function (
			x:Float, y:Float, w:Float, h:Float,
			ellipseWidth : Float, ?ellipseHeight : Float) : Void
		{
			if ( ellipseHeight==null ) {
				ellipseHeight = ellipseWidth;
			}
			var ewr:Float = ellipseWidth/2;
			var ehr:Float = ellipseHeight/2;
			//Bottom right
			obj.moveTo(x+ewr, y+h);
			obj.lineTo(x+w-ewr, y+h);
			obj.curveTo(x+w, y+h, x+w, y+h-ehr);
			//Top right
			obj.lineTo (x+w, y+ehr);
			obj.curveTo(x+w, y, x+w-ewr, y);
			//Top left
			obj.lineTo (x+ewr, y);
			obj.curveTo(x, y, x, y+ehr);
			//Bottom left
			obj.lineTo (x, y+h-ehr );
			obj.curveTo(x, y+h, x+ewr, y+h);
		}
	}

	// }}}
	
	// {{{ public static function __onMouseDown( obj:Dynamic ) : Dynamic

	public static function __onMouseDown( obj:Dynamic ) : Dynamic
	{
		return function () : Void
		{
			var root = flash.Lib.current._root;
			if ( obj.graphics.hitTest( root._xmouse, root._ymouse, true ) ) {
				var keys = obj.listeners.get(MouseEvent.MOUSE_DOWN);
				if ( keys.length>0 ) {
					var e:MouseEvent = new MouseEvent(MouseEvent.MOUSE_DOWN);
					e.target = obj;
					obj.dispatchEvent(e);
				}
			}
		}
	}

	// }}}
	// {{{ public static function __onMouseUp( obj:Dynamic ) : Dynamic

	public static function __onMouseUp( obj:Dynamic ) : Dynamic
	{
		return function () : Void
		{
			var root = flash.Lib.current._root;
			if ( obj.graphics.hitTest( root._xmouse, root._ymouse, true ) ) {
				var keys = obj.listeners.get(MouseEvent.MOUSE_UP);
				if ( keys.length>0 ) {
					var e:MouseEvent = new MouseEvent(MouseEvent.MOUSE_UP);
					e.target = obj;
					obj.dispatchEvent(e);
				}
				var keys = obj.listeners.get(MouseEvent.CLICK);
				if ( keys.length>0 ) {
					var e:MouseEvent = new MouseEvent(MouseEvent.CLICK);
					e.target = obj;
					obj.dispatchEvent(e);
				}
			}
		}
	}

	// }}}
	// {{{ public static function __onMouseMove( obj:Dynamic ) : Dynamic

	public static function __onMouseMove( obj:Dynamic ) : Dynamic
	{
		return function () : Void
		{
			var keys = obj.listeners.get(MouseEvent.MOUSE_MOVE);
			if ( keys.length>0 ) {
				var e:MouseEvent = new MouseEvent(MouseEvent.MOUSE_MOVE);
				e.target = obj;
				obj.dispatchEvent(e);
			}
		}
	}

	// }}}
	// {{{ public static function __onRollOver( obj:Dynamic ) : Dynamic

	public static function __onRollOver( obj:Dynamic ) : Dynamic
	{
		return function () : Void
		{
			var root = flash.Lib.current._root;
			if ( obj.graphics.hitTest( root._xmouse, root._ymouse, true ) ) {
				var keys = obj.listeners.get(MouseEvent.ROLL_OVER);
				if ( keys.length>0 ) {
					var e:MouseEvent = new MouseEvent(MouseEvent.ROLL_OVER);
					e.target = obj;
					obj.dispatchEvent(e);
				}
			}
		}
	}

	// }}}
	// {{{ public static function __onRollOut( obj:Dynamic ) : Dynamic

	public static function __onRollOut( obj:Dynamic ) : Dynamic
	{
		return function () : Void
		{
			var root = flash.Lib.current._root;
			if ( !obj.graphics.hitTest( root._xmouse, root._ymouse, true ) ) {
				var keys = obj.listeners.get(MouseEvent.ROLL_OUT);
				if ( keys.length>0 ) {
					var e:MouseEvent = new MouseEvent(MouseEvent.ROLL_OUT);
					e.target = obj;
					obj.dispatchEvent(e);
				}
			}
		}
	}

	// }}}
}
